package me.zhengjie.modules.system.rest

import cn.hutool.core.collection.CollectionUtil
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.servlet.http.HttpServletResponse
import me.zhengjie.common.exception.BadRequestException
import me.zhengjie.common.utils.*
import me.zhengjie.common.utils.EncryptUtils.encryptPassword
import me.zhengjie.common.utils.enums.CodeEnum
import me.zhengjie.logging.annotation.Log
import me.zhengjie.modules.system.domain.*
import me.zhengjie.modules.system.domain.vo.UserPassVo
import me.zhengjie.modules.system.service.*
import me.zhengjie.modules.system.service.dto.RoleSmallDTO
import me.zhengjie.modules.system.service.dto.UserDTO
import me.zhengjie.modules.system.service.dto.UserQueryCriteria
import org.springframework.data.domain.Pageable
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.util.CollectionUtils
import org.springframework.util.ObjectUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.io.IOException
import java.util.*
import java.util.stream.Collectors

/**
 * @author Kuki Wu
 * @date 2024-11-23
 */
@Schema(description = "系统：用户管理")
@RestController
@RequestMapping("/api/users")
class UserController(
    private val userService: UserService,
    private val dataService: DataService,
    private val deptService: DeptService,
    private val roleService: RoleService,
    private val verificationCodeService: VerifyService
) {
    @Log("导出用户数据")
    @Schema(description = "导出用户数据")
    @GetMapping(value = ["/download"])
    @PreAuthorize("@el.check('user:list')")
    @Throws(
        IOException::class
    )
    fun download(response: HttpServletResponse?, criteria: UserQueryCriteria?) {
        userService.download(userService.queryAll(criteria!!), response)
    }


    @Log("查询用户")
    @Schema(description = "查询用户")
    @GetMapping
    @PreAuthorize("@el.check('user:list')")
    fun getUsers(criteria: UserQueryCriteria, pageable: Pageable?): ResponseEntity<PageResult<UserDTO>> {
        if (!ObjectUtils.isEmpty(criteria.deptId)) {
            criteria.deptIds!!.add(criteria.deptId!!)
            // 先查找是否存在子节点
            val data: List<Dept?> = deptService.findByPid(criteria.deptId!!)
            // 然后把子节点的ID都加入到集合中
            criteria.deptIds!!.addAll(deptService.getDeptChildren(data) as Collection<Long>)
        }
        // 数据权限
        val dataScopes: List<Long?> = dataService.getDeptIds(userService.findByName(SecurityUtils.username)!!)!!
        // criteria.getDeptIds() 不为空并且数据权限不为空则取交集
        if (!CollectionUtils.isEmpty(criteria.deptIds) && !CollectionUtils.isEmpty(dataScopes)) {
            // 取交集
            criteria.deptIds!!.retainAll(dataScopes)
            if (!CollectionUtil.isEmpty(criteria.deptIds)) {
                return ResponseEntity(userService.queryAll(criteria, pageable) as PageResult<UserDTO>, HttpStatus.OK)
            }
        } else {
            // 否则取并集
            criteria.deptIds!!.addAll(dataScopes as Collection<Long>)
            return ResponseEntity(userService.queryAll(criteria, pageable) as PageResult<UserDTO>,  HttpStatus.OK)
        }
        return ResponseEntity(PageUtil.noData(), HttpStatus.OK)
    }

    @Log("使用用户名查询")
    @Schema(description = "使用用户名查询")
    @GetMapping(value = ["/findbyname/{username}"])
    //@PreAuthorize("@el.check('user:list')")
    @me.zhengjie.common.annotation.AnonymousAccess
    fun getByUserName(@PathVariable username: String?): ResponseEntity<Any> {
        val userdto = userService.findByName(username)
        return ResponseEntity(userdto, HttpStatus.OK)
    }
    @Log("新增用户")
    @Schema(description = "新增用户")
    @PostMapping
    @PreAuthorize("@el.check('user:add')")
    fun create(@Validated @RequestBody resources: User): ResponseEntity<Any> {
        checkLevel(resources)
        return ResponseEntity(userService.create(resources), HttpStatus.CREATED)
    }

    @Log("修改用户")
    @Schema(description = "修改用户")
    @PutMapping
    @PreAuthorize("@el.check('user:edit')")
    fun update(
        @Validated(
            User.Update::class
        ) @RequestBody resources: User
    ): ResponseEntity<*> {
        checkLevel(resources)
        userService.update(resources)
        return ResponseEntity<Any?>(HttpStatus.NO_CONTENT)
    }

    @Log("删除用户")
    @Schema(description = "删除用户")
    @DeleteMapping(value = ["/{id}"])
    @PreAuthorize("@el.check('user:del')")
    fun delete(@PathVariable id: Long?): ResponseEntity<*> {
        val currentLevel = Collections.min(
            roleService.findByUsersId(SecurityUtils.userId)!!.stream().map { obj: RoleSmallDTO? -> obj!!.level }
                .collect(Collectors.toList()) as Collection<Int>)
        val optLevel = Collections.min(
            roleService.findByUsersId(id!!)!!.stream().map { obj: RoleSmallDTO? -> obj!!.level }
                .collect(Collectors.toList()) as Collection<Int>
        )
        if (currentLevel > optLevel) {
            throw BadRequestException("角色权限不足")
        }
        userService.delete(id)
        return ResponseEntity<Any?>(HttpStatus.OK)
    }

    @Schema(description = "修改密码")
    @PostMapping(value = ["/updatePass"], consumes = [MediaType.APPLICATION_JSON_VALUE])
    fun updatePass(@RequestBody user: UserPassVo): ResponseEntity<*> {
        val userDetails = SecurityUtils.userDetails
        if (userDetails!!.password != encryptPassword(user.oldPass!!)) {
            throw BadRequestException("修改失败，旧密码错误")
        }
        if (userDetails!!.password == encryptPassword(user.newPass!!)) {
            throw BadRequestException("新密码不能与旧密码相同")
        }
        userService.updatePass(userDetails!!.username, encryptPassword(user.newPass!!))
        return ResponseEntity<Any?>(HttpStatus.OK)
    }

    @Schema(description = "修改头像")
    @PostMapping(value = ["/updateAvatar"])
    fun updateAvatar(@RequestParam file: MultipartFile?): ResponseEntity<*> {
        userService.updateAvatar(file!!)
        return ResponseEntity<Any?>(HttpStatus.OK)
    }

    @Log("修改邮箱")
    @Schema(description = "修改邮箱")
    @PostMapping(value = ["/updateEmail/{code}"])
    fun updateEmail(@PathVariable code: String, @RequestBody user: User): ResponseEntity<*> {
        val userDetails = SecurityUtils.userDetails
        if (userDetails!!.password != encryptPassword(user.password!!)) {
            throw BadRequestException("密码错误")
        }
        verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.key + user.email, code)
        userService.updateEmail(userDetails.username, user.email)
        return ResponseEntity<Any?>(HttpStatus.OK)
    }

    /**
     * 如果当前用户的角色级别低于创建用户的角色级别，则抛出权限不足的错误
     * @param resources /
     */
//    private fun checkLevel(resources: User) {
//        val currentLevel = Collections.min(
//            roleService.findByUsers_Id(SecurityUtils.userId!!)!!.stream().map { obj: RoleSmallDTO? -> obj!!.level }
//                .collect(Collectors.toList()) as Collection<Int>)
//        val optLevel = roleService.findByRoles(resources.roles!!)
//        if (currentLevel > optLevel) {
//            throw BadRequestException("角色权限不足")
//        }
//    }
    private fun checkLevel(resources: User) {
        val currentLevel:Int = roleService.findByUsersId(SecurityUtils.userId)!!
            .map { it!!.level }
            .minOfOrNull { it!! } ?: throw BadRequestException("角色无权限")

        val optLevel:Int = roleService.findByRoles(resources.roles!!)
        if (currentLevel > optLevel) {
            throw BadRequestException("角色权限不足")
        }
    }
}